#include <arpa/inet.h>
#include <argz.h>
#include <assert.h>
#include <malloc.h>
#include <string.h>
#include "hello.h"
#include "clientinfo.h"
#include "../hashtbl.h"

#define ASSERT assert
#define for_each(i, node, hash)  for (i = 0; i < (hash)->size; ++i) for (node = ((hash)->nodes)[i]; node; node = node->next)
uint32_t read_header(char * data)
{
	return ntohl(((uint32_t*)data)[0]);
}

uint32_t read_hello(HASHTBL *hash,
                    char * data,
                    size_t data_len) 
{
    uint32_t n, m;
	char * argz;
	size_t argz_len;
	
	if (data_len < HELLO_HEADER_SIZE) return 0;

	argz     = data     + HELLO_HEADER_SIZE;	
	argz_len = data_len - HELLO_HEADER_SIZE;

	n = read_header(data);

    if (n == 0) {
        return 0;
    }

    m = argz_count(data + HELLO_HEADER_SIZE, argz_len);

    if (n != m) {
        printf("\nn = %d != %d = m\n", n, m);
		return 0;
	}

	char * entry = NULL;
	while ((entry = argz_next(argz, argz_len, entry)))
	{
        if (hashtbl_res_insert(hash, entry, (void*)strdup(entry)) < 0) {
            printf("hashtbl_res_insert: -1\n");
            exit(EXIT_FAILURE);
        }
    }

	return n;
}

void write_header(char * dat, uint32_t n)
{
	uint32_t nn = htonl(n);
	char *p = (char*)(&nn);
	memcpy(dat, p, HELLO_HEADER_SIZE);
}

size_t write_hello(char ** buf, HASHTBL *hash_of_interests)
{
	uint32_t lab_size;
	char * argz;
	size_t argz_len;
    hash_size i, count;
    struct hashnode_s *hash_node;

    lab_size = hash_of_interests ? labsize(hash_of_interests) : 0;

	if ( !(*buf = malloc(lab_size + HELLO_HEADER_SIZE)) )
		return 0;

    count = hash_of_interests ? hash_of_interests->count : 0;
	
    write_header(*buf, count);

	argz     = NULL;
	argz_len = 0;

    if (!hash_of_interests) {
        return HELLO_HEADER_SIZE;
    }

    for_each(i, hash_node, hash_of_interests) {
        argz_add(&argz, &argz_len, (const char*)(hash_node->key));
    }

    memcpy(*buf + HELLO_HEADER_SIZE, argz, argz_len);
	ASSERT(argz_len == lab_size);

	return argz_len + HELLO_HEADER_SIZE;
}

void print_argz(char * buf, size_t buf_len)
{
    HASHTBL *hash;
    struct hashnode_s *node;
    hash_size i;
    hash = hashtbl_create(16, NULL);

    if (!read_hello(hash, buf, buf_len)) {
        printf("pusty pakiet hello\n");
        //return;
	}

    for( i = 0; i < hash->size; ++i ) {
        for ( node = (hash->nodes)[i];
              node; node = node->next ) {
            printf("   %s\n", node->key);
        }
    }

    hashtbl_destroy(hash);
}

size_t to_argz(char **buf, HASHTBL *hash)
{
        struct hashnode_s *node;
        char * argz = NULL;
        size_t argz_len = 0;
        hash_size i;
        for( i = 0; i < hash->size; ++i ) {
            for ( node = (hash->nodes)[i];
                  node; node = node->next ) {
                argz_add(&argz, &argz_len, node->key);
            }
        }
        *buf = argz;
        return argz_len;
}


//int main()
//{
//	char * argz,
//	     * test;
//	uint32_t   n,
//		   n_after;
//	size_t argz_len;
//    HASHTBL *hash;
//    hash_size i;
//    struct hashnode_s *node;
	
//	argz     = NULL;
//	argz_len = 0;
//	n        = 2;
//	argz_add(&argz, &argz_len, "piłka ręczna");
//	argz_add(&argz, &argz_len, "zapasy");

//	test = malloc((argz_len + 5) * sizeof(char));
//	write_header(test, n);

//	memcpy(test + HELLO_HEADER_SIZE, argz, argz_len);
//    n_after = read_hello(&hash, test, argz_len + HELLO_HEADER_SIZE);
	
//        printf("%d\n", n_after);
//    ASSERT( n_after    == n );

//    for( i = 0; i < hash->size; ++i ) {
//        for ( node = (hash->nodes)[i]; node; node = node->next ) {
//            printf("ETYKIETA: %s\n", node->key);
//        }
//    }

//    printf("labsize = %d", labsize(hash));
//    size_t l = strlen("piłka ręczna") + strlen("zapasy") + 2 + 4;
//	char *buf = calloc(l, sizeof(char));
//    write_hello(buf, hash);
//    print_hello(buf, hash);
//	return 0;
//}
